<template>
    <el-dialog v-model="isShowDialog" title="选择" width="800px" height="800px" @close="handleCancel"
        :close-on-click-modal="false">
        <el-row>
            <el-col :span=14 style="padding-right:20px;">
                <el-input @keyup.enter="search" @clear="search" v-model="searchParam.keyword" clearable
                    style="margin-bottom: 10px" :prefix-icon="Search" size="large" placeholder="回车检索" />
                <el-table ref="tableRef" :data="tableData" v-loading="loading" @select="select" @select-all="selectAll"
                    style=" border:1px solid #dcdfe6; height:390px;" @row-dblclick="rowDblclick">
                    <el-table-column type="selection" width="30" />
                    <el-table-column prop="title" label="内容" show-overflow-tooltip />
                </el-table>
                <MkPagination v-model:page="searchParam.page" v-model:pageSize="searchParam.pageSize" :total="total"
                    layout="total, sizes, prev, pager, next" @query="search" />
            </el-col>
            <el-col :span=10 style="padding:0px">
                <el-table :data="selectedTable" :show-header="false" style="border:1px solid #dcdfe6;height:460px;">
                    <el-table-column prop="title" label="内容" show-overflow-tooltip />
                    <el-table-column fixed="right" label="Operations" width="30">
                        <template #default="scope">
                            <el-button link type="primary" size="small" @click="del(scope.row)">
                                <el-icon>
                                    <Close />
                                </el-icon>
                            </el-button>
                        </template>
                    </el-table-column>
                </el-table>
            </el-col>
        </el-row>
        <template #footer>
            <slot name="footer">
                <el-button @click="handleCancel"> 取 消</el-button>
                <el-button @click="handleConfirm" type="primary"> 确 定</el-button>
            </slot>
        </template>
    </el-dialog>
</template>
<script lang="ts" setup>
// 多选对话框, 只支持关键字的分页检索, 检索得到的数据必须带有id字段, 根据id字段去重
// 组件
import { Search, Close } from '@element-plus/icons-vue'
import { ElInput, ElTableColumn, ElTable, ElCol, ElIcon, ElButton, ElDialog, ElRow, vLoading } from 'element-plus';
import MkPagination from '/@/componentsMaike/tables/MkPagination.vue'
// hooks
import { usePageQuery } from '/@/hooks/usePageQuery'
// 工具
import { clog } from '/@/utils/index'

defineOptions({
    name: 'MkMultiSelect'
})

// 传入的配置项
const config = ref({
    confirmCallback: (list: any) => { },
    cancelCallback: () => { },
    destory: () => { }
})

//待选择数据必须有id字段
interface Model {
    id: any
}

const fnOnSearchFinish = () => {
    nextTick(() => {
        tableData.value.forEach((row) => {
            if (selectedIds.has(row.id)) {
                //选中已经选择的行
                tableRef.value!.toggleRowSelection(row, true)
            }
        })
    })
}

const props = defineProps({
    searchFun: { type: Function, required: true },
})
const { searchParam, total, tableData, loading, search } = usePageQuery<Model>(props.searchFun, fnOnSearchFinish)

const isShowDialog = ref(false)
const tableRef = ref()


const selectedTable = ref<Model[]>([])
let selectedIds = new Set();//已选数据索引

// 钩子函数
onMounted(() => {
    // search()
})

const open = async (row: any) => {
    selectedTable.value = [];
    selectedIds = new Set();
    searchParam.keyword = ""
    search();
    isShowDialog.value = true
};


//单个选中/取消
const select = (selection: Model[], row: Model) => {
    console.log(selection, row);

    let index = selection.indexOf(row); //判断是选中还是取消
    if (index > -1) {
        // 选中了行
        if (selectedIds.has(row.id)) return;
        selectedTable.value.push(row);
        selectedIds.add(row.id)
    } else {
        // 取消选中
        let index2 = selectedTable.value.indexOf(row);
        selectedTable.value.splice(index2, 1);
        selectedIds.delete(row.id)
    }
}
// 列表双击
const rowDblclick = (row: any) => {
    tableRef.value!.toggleRowSelection(row)
    console.log(tableRef.value.getSelectionRows());

    select(tableRef.value.getSelectionRows(), row)
}
//批量选中/取消
const selectAll = (selection: Model[]) => {
    delRows(tableData.value);// 先删除所有待选
    addRows(selection); //再添加选中的
}

const addRows = (rows: Model[]) => {
    rows.forEach(row => {
        if (!selectedIds.has(row.id)) {
            selectedTable.value.push(row);
            selectedIds.add(row.id)
        }
    })
}

const delRows = (rows: Model[]) => {
    rows.forEach(row => {
        selectedIds.delete(row.id)
    })

    //把不需要删除的暂存到一个新数组,而非从原数组删除,以提高性能
    //当删除元素很多时, 性能提升明显, 当删除元素较少时, 性能不变, 因为数组的删除操作是O(n)
    var newSelected: Model[] = []
    selectedTable.value.forEach(row => {
        if (selectedIds.has(row.id)) {
            newSelected.push(row)
        }
    })
    selectedTable.value = newSelected;
}

const del = (row: any) => {
    let index = selectedTable.value.indexOf(row);
    if (index >= 0) {
        selectedTable.value.splice(index, 1);
        tableData.value.forEach((row2) => {
            if (row2.id == row.id) {
                //选中已经选择的行
                tableRef.value!.toggleRowSelection(row2, false)
            }
        })
        selectedIds.delete(row.id)
    }
}

const handleConfirm = () => {
    clog('handleConfirm', selectedTable.value);

    config.value.confirmCallback(selectedTable.value)
    config.value.destory()
    isShowDialog.value = false
}

const handleCancel = () => {
    config.value.cancelCallback()
    config.value.destory()
    isShowDialog.value = false;
};

defineExpose({
    open, config
})

</script>